using BepuUtilities;
using BepuUtilities.Collections;
using BepuUtilities.Memory;
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
#if MYCODE
using BepuUtilities.Vectors;
#else
using System.Numerics;
#endif
namespace BepuPhysics.Trees
{
    partial struct Tree
    {

        unsafe float RefitAndMeasure(ref NodeChild child)
        {
            ref var node = ref Nodes[child.Index];

            // 所有节点保证至少有2个子节点。
            Debug.Assert(leafCount >= 2);

            var premetric = ComputeBoundsMetric(ref child.Min, ref child.Max);
            float childChange = 0;
            ref var a = ref node.A;
            if (a.Index >= 0)
            {
                childChange += RefitAndMeasure(ref a);
            }
            ref var b = ref node.B;
            if (b.Index >= 0)
            {
                childChange += RefitAndMeasure(ref b);
            }
            BoundingBox.CreateMerged(a.Min, a.Max, b.Min, b.Max, out child.Min, out child.Max);

            var postmetric = ComputeBoundsMetric(ref child.Min, ref child.Max);
            return postmetric - premetric + childChange; // 待办事项：夹紧会产生更好的效果吗？

        }

        unsafe float RefitAndMark(ref NodeChild child, int leafCountThreshold, ref QuickList<int> refinementCandidates, BufferPool pool)
        {
            Debug.Assert(leafCountThreshold > 1);

            ref var node = ref Nodes[child.Index];
            Debug.Assert(Metanodes[child.Index].RefineFlag == 0);
            float childChange = 0;

            var premetric = ComputeBoundsMetric(ref child.Min, ref child.Max);
            // 内部节点的波前由大于阈值到小于阈值的过渡来定义。
            // 将它们添加到优化候选列表中。
            // 请注意,不包括叶子,因为它们不能作为细化候选者。
            ref var a = ref node.A;
            if (a.Index >= 0)
            {
                if (a.LeafCount <= leafCountThreshold)
                {
                    refinementCandidates.Add(a.Index, pool);
                    childChange += RefitAndMeasure(ref a);
                }
                else
                {
                    childChange += RefitAndMark(ref a, leafCountThreshold, ref refinementCandidates, pool);
                }
            }
            ref var b = ref node.B;
            if (b.Index >= 0)
            {
                if (b.LeafCount <= leafCountThreshold)
                {
                    refinementCandidates.Add(b.Index, pool);
                    childChange += RefitAndMeasure(ref b);
                }
                else
                {
                    childChange += RefitAndMark(ref b, leafCountThreshold, ref refinementCandidates, pool);
                }
            }

            BoundingBox.CreateMerged(a.Min, a.Max, b.Min, b.Max, out child.Min, out child.Max);


            var postmetric = ComputeBoundsMetric(ref child.Min, ref child.Max);

            return postmetric - premetric + childChange; // 待办事项：钳子会带来更好的效果吗？



        }

        unsafe float RefitAndMark(int leafCountThreshold, ref QuickList<int> refinementCandidates, BufferPool pool)
        {
            Debug.Assert(LeafCount > 2, "There's no reason to refit a tree with 2 or less elements. Nothing would happen.");

            ref var children = ref Nodes[0].A;
            float childChange = 0;
            BoundingBox merged = new BoundingBox { Min = new Vector3(float.MaxValue), Max = new Vector3(float.MinValue) };
            for (int i = 0; i < 2; ++i)
            {
                // 注意：这些条件意味着根永远不会被视为波前节点。这是可以接受的;
                // 不管怎样,它都会被包括在内。
                ref var child = ref Unsafe.Add(ref children, i);
                if (child.Index >= 0)
                {
                    if (child.LeafCount <= leafCountThreshold)
                    {
                        // 内部节点的波前由大于阈值到小于阈值的过渡来定义。
                        // 因为我们不遍历这些子代,所以没有必要检查父代的叶数。
                        refinementCandidates.Add(child.Index, pool);
                        childChange += RefitAndMeasure(ref child);
                    }
                    else
                    {
                        childChange += RefitAndMark(ref child, leafCountThreshold, ref refinementCandidates, pool);
                    }
                }
                BoundingBox.CreateMerged(child.Min, child.Max, merged.Min, merged.Max, out merged.Min, out merged.Max);
            }

            var postmetric = ComputeBoundsMetric(ref merged);

            // 请注意,不包括根用户自己的更改。
            // 此成本变化用于确定是否细化。
            // 由于细化无法更改根的体积,因此存在
            // 把它包括在音量变化中是没有意义的。
            // 但是,它确实将子卷更改归一化为成本度量。
            if (postmetric >= 1e-10)
            {
                return childChange / postmetric;
            }
            return 0;
        }




        unsafe void ValidateRefineFlags(int index)
        {
            ref var metanode = ref Metanodes[index];
            if (metanode.RefineFlag != 0)
                Console.WriteLine("Bad refine flag");

            ref var children = ref Nodes[index].A;
            for (int i = 0; i < 2; ++i)
            {
                ref var child = ref Unsafe.Add(ref children, i);
                if (child.Index >= 0)
                {
                    ValidateRefineFlags(child.Index);
                }
            }
        }

        void GetRefitAndMarkTuning(out int maximumSubtrees, out int estimatedRefinementCandidateCount, out int refinementLeafCountThreshold)
        {
            maximumSubtrees = (int)(Math.Sqrt(leafCount) * 3);
            estimatedRefinementCandidateCount = (leafCount * 2) / maximumSubtrees;

            refinementLeafCountThreshold = Math.Min(leafCount, maximumSubtrees);
        }

        void GetRefineTuning(int frameIndex, int refinementCandidatesCount, float refineAggressivenessScale, float costChange,
            out int targetRefinementCount, out int refinementPeriod, out int refinementOffset)
        {
            if (float.IsNaN(costChange) || float.IsInfinity(costChange))
                throw new InvalidOperationException(
                    "The change in tree cost is an invalid value, strongly implying the tree bounds have been corrupted by infinites or NaNs. " +
                    "If this happened in the broad phase's use of the tree, it's likely that there are invalid poses or velocities in the simulation, " +
                    "possibly as a result of bugged input state or constraint configuration. " +
                    "Try running the library with debug asserts enabled to narrow down where the NaNsplosion started.");
            var refineAggressiveness = Math.Max(0, costChange * refineAggressivenessScale);
            float refinePortion = Math.Min(1, refineAggressiveness * 0.25f);

            var targetRefinementScale = Math.Min(nodeCount, Math.Max(2, (float)Math.Ceiling(refinementCandidatesCount * 0.03f)) + refinementCandidatesCount * refinePortion);
            // 请注意,为了简单起见,refinementCandidatesCount用作最大值,而不是finementCandidate+1,因为有可能
            // 根应该已经是一个细化的Candidate。无论哪种方式都不会有显著的效果。
            refinementPeriod = Math.Max(1, (int)(refinementCandidatesCount / targetRefinementScale));
            refinementOffset = (int)((frameIndex * 236887691L + 104395303L) % Math.Max(1, refinementCandidatesCount));
            targetRefinementCount = Math.Min(refinementCandidatesCount, (int)targetRefinementScale);
        }

        public int GetCacheOptimizeTuning(int maximumSubtrees, float costChange, float cacheOptimizeAggressivenessScale)
        {
            // TODO：使用成本变化作为高速缓存优化的启发式方法不是一个好主意。它们并不总是相关的,甚至不是经常相关的。
            // 最好的启发式方法是直接测量邻接度。我们可以在改装时做这件事。我还没有谈到这个问题
            // 因为缓存优化方法很可能会发生重大变化(例如,将输出重新调整为具有启发式完美布局的新树)。
            var cacheOptimizeAggressiveness = Math.Max(0, costChange * cacheOptimizeAggressivenessScale);
            float cacheOptimizePortion = Math.Min(1, 0.03f + 85f * (maximumSubtrees / (float)leafCount) * cacheOptimizeAggressiveness);
            // 浮点cacheOptimizePortion=Math.Min(1,0.03f+cacheOptimizeAggressitivity*0.5F);
            // Console.WriteLine($"缓存优化部分：{cacheOptimizePortion}");
            return (int)Math.Ceiling(cacheOptimizePortion * nodeCount);
        }



        public unsafe void RefitAndRefine(BufferPool pool, int frameIndex, float refineAggressivenessScale = 1, float cacheOptimizeAggressivenessScale = 1)
        {
            // 如果采油树不需要改装或改进,请不要继续。这也保证了任何确实存在的节点都有两个子节点。
            if (leafCount <= 2)
                return;
            GetRefitAndMarkTuning(out int maximumSubtrees, out int estimatedRefinementCandidateCount, out int leafCountThreshold);
            var refinementCandidates = new QuickList<int>(estimatedRefinementCandidateCount, pool);

            // 收集提炼候选人。
            var costChange = RefitAndMark(leafCountThreshold, ref refinementCandidates, pool);


            GetRefineTuning(frameIndex, refinementCandidates.Count, refineAggressivenessScale, costChange, out int targetRefinementCount, out int period, out int offset);


            var refinementTargets = new QuickList<int>(targetRefinementCount, pool);

            int index = offset;
            for (int i = 0; i < targetRefinementCount - 1; ++i)
            {
                index += period;
                if (index >= refinementCandidates.Count)
                    index -= refinementCandidates.Count;
                refinementTargets.AddUnsafely(refinementCandidates[index]);
                Debug.Assert(Metanodes[refinementCandidates[index]].RefineFlag == 0, "Refinement target search shouldn't run into the same node twice!");
                Metanodes[refinementCandidates[index]].RefineFlag = 1;
            }
            refinementCandidates.Dispose(pool);
            if (Metanodes[0].RefineFlag == 0)
            {
                refinementTargets.AddUnsafely(0);
                Metanodes[0].RefineFlag = 1;
            }

            // 细化所有标记的目标。

            var subtreeReferences = new QuickList<int>(maximumSubtrees, pool);
            var treeletInternalNodes = new QuickList<int>(maximumSubtrees, pool);

            CreateBinnedResources(pool, maximumSubtrees, out var buffer, out var resources);

            for (int i = 0; i < refinementTargets.Count; ++i)
            {

                subtreeReferences.Count = 0;
                treeletInternalNodes.Count = 0;
                BinnedRefine(refinementTargets[i], ref subtreeReferences, maximumSubtrees, ref treeletInternalNodes, ref resources, pool);
                // TODO：是否应该将其移动到后期循环中？它可以允许一些双重工作,但这并不可怕。
                // 从多线程的角度来看,它也不是无效的-将细化标志设置为零实质上就是解锁。
                // 如果其他线程由于缓存问题而没有看到它更新,这并不重要-它不是一个信号或任何类似的东西。
                Metanodes[refinementTargets[i]].RefineFlag = 0;

            }

            pool.Return(ref buffer);
            subtreeReferences.Dispose(pool);
            treeletInternalNodes.Dispose(pool);
            refinementTargets.Dispose(pool);

            var cacheOptimizeCount = GetCacheOptimizeTuning(maximumSubtrees, costChange, cacheOptimizeAggressivenessScale);

            var startIndex = (int)(((long)frameIndex * cacheOptimizeCount) % nodeCount);

            // 我们可以绕着走。但是我们也可以不这么做,因为这真的无关紧要！
            var end = Math.Min(NodeCount, startIndex + cacheOptimizeCount);
            for (int i = startIndex; i < end; ++i)
            {
                IncrementalCacheOptimize(i);
            }

        }




    }
}
